import numpy as np 

# 神经网络激活函数=========================================
# 1.一般层激活函数
def step_function(x):
    '''阶跃激活函数
    
    根据向量x分量是否大于0，返回一个分量为0,1的向量
    '''
    return np.array(x>0,dtype=np.int32)

def sigmoid(x):
    '''sigmoid激活函数
    根据向量x的分量，返回一个介于0-1之间的实数构成的向量
    '''
    return 1/(1+np.exp(-x))

def sigmoid_grad(x):
    return (1.0-sigmoid(x))*sigmoid(x)

def relu(x):
    '''relu激活函数
    对输入大于0的分量，直接输出该值；
    在输入小于0的分量，输出为0
    '''
    return np.maximum(0,x)

# 2. 输出层激活函数
def identity_function(x):
    '''输出层激活函数
    回归问题使用的恒等函数
    '''
    return x 

def softmax(x):
    '''输出层激活函数
    分类问题使用的softmax函数'''
    if x.ndim == 2:
        x = x.T
        x = x-np.max(x,axis=0)
        y = np.exp(x)/np.sum(np.exp(x),axis=0)
        return y.T
    x = x - np.max(x)
    return np.exp(x)/np.sum(np.exp(x))
#=================================================

# 损失函数==========================================

# 均方误差损失函数
def mean_squared_error(y,t):
    '''均方误差损失函数
    Parameters:
    -----------------------
    y: 神经网络的输出
    t: 标签数据
    
    Returns：
    -----------------------
    返回网络输出与标签数据均方误差的大小
    '''
    return 0.5*np.sum((y-t)**2)

# 交叉熵损失函数
def cross_entropy_error(y,t):
    '''交叉熵损失函数
    无论t是否为one-hot-lable,均转换成非one-hot进行处理
    '''
    if y.ndim == 1:
        t = t.reshape(1,t.size)
        y = y.reshape(1,y.size)
    
    # 将监督数据是one-hot-vector，转换为正确的标签索引
    if t.size == y.size:
        t = t.argmax(axis=1)

    batch_size = y.shape[0]
    return -np.sum(np.log(y[np.arange(batch_size),t]+1e-7))/batch_size

if __name__ == '__main__':
    t = np.array([0, 0, 1, 0, 0, 0, 0, 0, 0, 0])
    y = np.array([0.1, 0.05, 0.6, 0.0, 0.05, 0.1, 0.0, 0.1, 0.0, 0.0])
    print(cross_entropy_error(y,t))
